package cn.tedu.mall.front.service.impl;

import cn.tedu.mall.common.exception.CoolSharkServiceException;
import cn.tedu.mall.common.restful.ResponseCode;
import cn.tedu.mall.front.service.IFrontCategoryService;
import cn.tedu.mall.pojo.front.entity.FrontCategoryEntity;
import cn.tedu.mall.pojo.front.vo.FrontCategoryTreeVO;
import cn.tedu.mall.pojo.product.vo.CategoryStandardVO;
import cn.tedu.mall.product.service.front.IForFrontCategoryService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@DubboService
@Service
@Slf4j
public class FrontCategoryServiceImpl implements IFrontCategoryService {
    //定义Redis的Key
    public static final String CATEGORY_TREE_KEY="category:tree";
    @Autowired
    private RedisTemplate redisTemplate;
    //需要远程调用product中的方法，使用Dubbo
    @DubboReference
    private IForFrontCategoryService dubboForFrontCategoryService;

    /*
    1. 需要判断Redis中是否有分类信息，如果有直接返回，如果没有，再执行以下步骤
    2. 从数据库中查询所有分类信息--product
    3. 构建分类信息的父子结构，实现查询返回父子结构的分类信息
    4. 将要查询的结果保存到Redis中，以备后续用户直接获取分类信息
     */
    @Override
    public FrontCategoryTreeVO categoryTree() {
        //1.需要判断Redis中是否有分类信息
        //判断Redis中是否包含CATEGORY_TREE_KEY
        if (redisTemplate.hasKey(CATEGORY_TREE_KEY)){
            //已经包含这个可以，直接返回分类信息
            FrontCategoryTreeVO treeVO =
                    (FrontCategoryTreeVO) redisTemplate.boundValueOps(CATEGORY_TREE_KEY).get();
            return treeVO;
        }
        //代码到此处，表示Redis中没有分类信息
        //2.从数据库中查询所有分类数据
        List<CategoryStandardVO> categoryStandardVOS =  dubboForFrontCategoryService.getCategoryList();
        //3.构建分类信息的父子结构--三级分类树
        FrontCategoryTreeVO<FrontCategoryEntity> treeVO = initTree(categoryStandardVOS);
        //4.将要查询的结果保存到Redis中，以备后续用户直接获取分类信息
        redisTemplate.boundValueOps(CATEGORY_TREE_KEY).set(treeVO,60*60*24*30, TimeUnit.SECONDS);
        //千万别忘记返回
        return treeVO;
    }
    //构建三级分类树
    private FrontCategoryTreeVO<FrontCategoryEntity> initTree(List<CategoryStandardVO> categoryStandardVOS) {
        //第一部分：确定所有分类对象的父分类
        //声明一个map，使用父分类id为key，所有子分类为value(List)
        Map<Long,List<FrontCategoryEntity>> map = new HashMap<>();
        log.info("当前分类地下的总和为：{}",categoryStandardVOS.size());
        //遍历categoryStandardVOS
        for (CategoryStandardVO categoryStandardVO : categoryStandardVOS) {
            //categoryStandardVO中没有children属性，需要转换成FrontCategoryEntity类型
            FrontCategoryEntity frontCategoryEntity = new FrontCategoryEntity();
            //利用BeanUtils做同名属性赋值
            BeanUtils.copyProperties(categoryStandardVO,frontCategoryEntity);
            //使用parent_id做为map的key
            Long parentId = frontCategoryEntity.getParentId();
            //判断map中是否已经包含该key
            if (map.containsKey(parentId)){
                //已经包含该key，直接添加到value的list集合中
                map.get(parentId).add(frontCategoryEntity);
            } else {
                //没有这个key，使用parentId为key值
                //value是List类型的，我们需要创建List类型的value对象
                List<FrontCategoryEntity> value = new ArrayList<>();
                value.add(frontCategoryEntity);
                map.put(parentId,value);
            }
        }
        //第二部分:将子分类对象管理到父分类的children属性中
        //从map中根据key(父分类ID)找到所有子分类对象
        //根分类对象--一级分类--父分类id是0
        List<FrontCategoryEntity> firstLevels = map.get(0L);
        //判断一级分类集合是否为null
        if(firstLevels==null)
            throw new CoolSharkServiceException(ResponseCode.INTERNAL_SERVER_ERROR,"当前项目没有根分类");
        //遍历一级分类集合
        for (FrontCategoryEntity firstLevel : firstLevels) {
            //一级分类对象的id是二级分类对象的父分类id
            Long secondParentId = firstLevel.getId();
            //根据secondParentId获取二级分类对象集合
            List<FrontCategoryEntity> secondLevels = map.get(secondParentId);
            //判断二级分类对象集合是否为null
            if(secondLevels==null){
                log.warn("当前分类缺少二级分类对象，{}",firstLevel);
                //结束本次循环，继续下一次循环
                continue;
            }
            //遍历二级集合
            for (FrontCategoryEntity secondLevel : secondLevels) {
                //获取二级集合对象的id，作为三级集合对象的父分类id
                Long thirdParentId = secondLevel.getId();
                //获取三级分类对象集合
                List<FrontCategoryEntity> thirdLevels = map.get(thirdParentId);
                //判断三级分类对象集合是否为null
                if(thirdLevels==null){
                    log.warn("当前分类缺少三级分类对象，{}",secondLevel);
                    //结束本次循环，继续下一次循环
                    continue;
                }
                //将三级集合对象添加到二级集合中的children属性中
                secondLevel.setChildrens(thirdLevels);
            }
            //将二级集合对象添加到一级集合中的children属性中
            firstLevel.setChildrens(secondLevels);
        }
        //到此为止，分类信息的树结构构建完成
        //但是我们需要返回的FrontCategoryTreeVO<FrontCategoryEntity>类型
        FrontCategoryTreeVO<FrontCategoryEntity>  treeVO = new FrontCategoryTreeVO<>();
        //将一级集合对象添加到treeVO的属性中
        treeVO.setCategories(firstLevels);
        return treeVO;
    }
}
